package com.maoye.ossp.bpm.defmanager.controller;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.hotent.base.api.query.Direction;
import com.hotent.base.api.query.FieldLogic;
import com.hotent.base.api.query.FieldRelation;
import com.hotent.base.api.query.FieldSort;
import com.hotent.base.api.query.QueryOP;
import com.hotent.base.core.util.BeanUtils;
import com.hotent.base.core.util.string.StringUtil;
import com.hotent.base.db.model.DefaultFieldLogic;
import com.hotent.base.db.model.DefaultQueryFilter;
import com.hotent.base.db.mybatis.domain.DefaultFieldSort;
import com.hotent.base.db.mybatis.domain.PageList;
import com.hotent.bpmx.api.constant.DesignerType;
import com.hotent.bpmx.api.context.ContextUtil;
import com.hotent.bpmx.api.model.process.def.BpmDefExtProperties;
import com.hotent.bpmx.api.model.process.def.BpmDefLayout;
import com.hotent.bpmx.api.model.process.def.BpmDefinition;
import com.hotent.bpmx.api.model.process.def.BpmProcessDef;
import com.hotent.bpmx.api.model.process.def.BpmProcessDefExt;
import com.hotent.bpmx.api.service.BpmDefHandler;
import com.hotent.bpmx.api.service.BpmDefinitionService;
import com.hotent.bpmx.api.service.BpmInstService;
import com.hotent.bpmx.api.service.DiagramService;
import com.hotent.bpmx.api.service.FlowStatusService;
import com.hotent.bpmx.persistence.manager.BpmDefinitionManager;
import com.hotent.bpmx.persistence.model.BpmDefData;
import com.hotent.bpmx.persistence.model.DefaultBpmDefinition;
import com.hotent.org.api.model.User;
import com.maoye.ossp.bpm.defmanager.service.BpmDefVarsService;
import com.maoye.ossp.bpm.defmanager.utils.ProcessDefExtUtil2;
import com.maoye.ossp.bpm.defmanager.utils.RequestUtil;
import com.maoye.ossp.common.entity.Page;
import com.maoye.ossp.common.web.BaseController;
import com.maoye.ossp.sys.org.util.UserUtils;

/**
 * 
 * <pre>
 * 描述：流程定义管理
 * 构建组：x5-bpmx-platform
 * 作者:zyp
 * 邮箱:zyp@jee-soft.cn
 * 日期:2014-1-10-下午3:29:34
 * 版权：广州宏天软件有限公司版权所有
 * </pre>
 */
@Controller
@RequestMapping("/bpm/def/definition/")
public class BpmDefinitionController extends BaseController {
	private static final String LIST_CALL_IN_MESSAGE = "list_call_in_message";
	@Resource
	BpmDefinitionManager bpmDefinitionManager;
	@Resource
	BpmDefinitionService bpmDefinitionService;
	@Resource
	DiagramService diagramService;
	@Resource
	FlowStatusService flowStatusService;
	@Resource
	BpmDefVarsService bpmDefVarsService;
	@Resource
	BpmDefHandler bpmDefHandler;
	@Resource
	BpmInstService bpmInstService;

	@RequestMapping(value = "bpmImage")
	public void bpmImage(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0L);

		String defId = request.getParameter("defId");
		String instanceId = request.getParameter("instanceId");
		InputStream is = null;

		// if (StringUtil.isEmpty(defId)) {
		// if (StringUtil.isNotEmpty(instanceId)) {
		// BpmProcessInstance bpmProcessInstance =
		// bpmInstService.getProcessInstance(instanceId);
		// if (bpmProcessInstance != null) {
		// defId = bpmProcessInstance.getProcDefId();
		// }
		// }
		// }

		if (StringUtil.isNotEmpty(defId)) {
			if (StringUtil.isNotEmpty(instanceId)) {
				Map<String, String> status = flowStatusService
						.getProcessInstanceStatus(instanceId);
				is = diagramService.getDiagramByBpmnDefId(defId, status);
			} else {
				is = diagramService.getDiagramByBpmnDefId(defId);
			}
		}
		if (is != null) {
			response.setContentType("image/png");
			OutputStream out = new BufferedOutputStream(
					response.getOutputStream());
			try {
				byte b[] = new byte[1024];
				while (is.read(b) > 0) {
					out.write(b);
				}
			} finally {
				is.close();
				out.close();
			}
		}
	}

	/**
	 * 保存系统用户信息
	 * 
	 * @param request
	 * @param response
	 * @param bpmDef
	 * @param redirectAttributes
	 * @throws Exception
	 */
	@RequestMapping("save")
	public String save(HttpServletRequest request,
			HttpServletResponse response,
			@ModelAttribute ProcessDefExtUtil2 bpmDefUtil,
			RedirectAttributes redirectAttributes) throws Exception {
		String resultMsg = null;
		Map<String, String> vars = bindingVars(request);
		if (vars.size() > 0) {
			request.setAttribute("vars", vars);
		}
		String isDeploy = request.getParameter("isDeploy");
		String isSave = request.getParameter("isSave");

		DefaultBpmDefinition bpmDefinition = bpmDefUtil.getBpmDefinition();
		BpmDefExtProperties extProperties = bpmDefUtil.getExtProperties();

		bpmDefinition.setIsMain("Y");
		bpmDefinition.setDesigner(DesignerType.FLASH.name());
		Long userIdL = UserUtils.getCurrentUserId();
		String userIdS = userIdL == null ? "" : userIdL.toString();
		try {
			if ("true".equals(isDeploy)) {// deploy
				if (StringUtils.isNotEmpty(bpmDefUtil.getBpmDefinition()
						.getDefId())) {
					DefaultBpmDefinition oldBpmDefinition = bpmDefinitionManager
							.getByDefIdCascadeXml(bpmDefUtil.getBpmDefinition()
									.getDefId());
					BpmDefData defData = oldBpmDefinition.getBpmDefData();
					BeanUtils.copyNotNullProperties(oldBpmDefinition,
							bpmDefinition);
					oldBpmDefinition.setBpmDefData(defData);
					bpmDefinitionService.deploy(oldBpmDefinition);
					bpmDefHandler.saveProProperties(bpmDefUtil
							.getBpmDefinition().getDefId(), extProperties);
					bpmDefVarsService.save(vars, oldBpmDefinition.getDefId());
					resultMsg = "成功发布新版本流程定义！";
				} else {
					bpmDefinitionService.deploy(bpmDefinition);
					bpmDefVarsService.save(vars, bpmDefUtil.getBpmDefinition()
							.getDefId());
					resultMsg = "成功发布流程定义！";
				}
			} else if ("true".equals(isSave)
					&& StringUtils.isNotEmpty(bpmDefUtil.getBpmDefinition()
							.getDefId())) {
				DefaultBpmDefinition oldBpmDefinition = bpmDefinitionManager
						.getById(bpmDefUtil.getBpmDefinition().getDefId());
				BpmDefData defData = oldBpmDefinition.getBpmDefData();
				bpmDefinition.setBpmDefData(defData);
				BeanUtils
						.copyNotNullProperties(oldBpmDefinition, bpmDefinition);
				// oldBpmDefinition.setBpmDefData(defData);
				bpmDefinitionService.updateBpmDefinition(oldBpmDefinition);
				bpmDefVarsService.save(vars, oldBpmDefinition.getDefId());
				bpmDefHandler.saveProProperties(bpmDefUtil.getBpmDefinition()
						.getDefId(), extProperties);
				resultMsg = "成功更新流程定义！";
			} else {// 保存草稿
				bpmDefinition.setCreateBy(userIdS);
				bpmDefinitionService.saveDraft(bpmDefinition);
				bpmDefVarsService.save(vars, bpmDefUtil.getBpmDefinition()
						.getDefId());
				bpmDefHandler.saveProProperties(bpmDefUtil.getBpmDefinition()
						.getDefId(), extProperties);
				resultMsg = "成功保存流程定义草稿！";
			}
			addMessage(redirectAttributes, resultMsg);
		} catch (Exception e) {
			e.printStackTrace();
			addMessage(redirectAttributes, "操作出错：" + e.getMessage());
		}
		request.setAttribute("bpmDefUtil", bpmDefUtil);
		return "redirect:/bpm/def/definition/list";
	}

	@SuppressWarnings("unchecked")
	private Map<String, String> bindingVars(HttpServletRequest request) {
		Iterator<Map.Entry<String, String>> iterator = request
				.getParameterMap().entrySet().iterator();
		Map<String, String> vars = new HashMap<String, String>();
		String name;
		while (iterator.hasNext()) {
			Entry<String, String> entry = iterator.next();
			if ((name = entry.getKey()).startsWith("vars.")) {
				vars.put(name.substring(5), request.getParameter(name));
			}
		}
		return vars;
	}

	/**
	 * 编辑流程定义页面
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("{defId}/view")
	public String view(HttpServletRequest request,
			HttpServletResponse response, @PathVariable String defId)
			throws Exception {
		BpmDefinition def = bpmDefinitionService.getBpmDefinitionByDefId(defId);
		request.setAttribute("bpmDef", def);
		request.setAttribute("vars", bpmDefVarsService.selectMap(defId));
		if (StringUtil.isNotEmpty(def.getBpmnDefId())) {
			BpmDefLayout layout = diagramService.getLayoutByDefId(def
					.getDefId());
			request.setAttribute("bpmDefLayout", layout);
		}
		return "/bpm/def/definition/definitionView";
	}

	/**
	 * 添加流程定义页面
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("add")
	public String add(HttpServletRequest request, HttpServletResponse response,
			DefaultBpmDefinition bpmDef) throws Exception {
		request.setAttribute("bpmDef", bpmDef);
		return "/bpm/def/definition/definitionEdit";
	}

	/**
	 * 编辑流程定义页面
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("{defId}/edit")
	public String edit(HttpServletRequest request,
			HttpServletResponse response, @PathVariable String defId,
			DefaultBpmDefinition bpmDef) throws Exception {
		DefaultBpmDefinition def = (DefaultBpmDefinition) bpmDefinitionService
				.getBpmDefinitionByDefId(defId);
		BpmProcessDef<BpmProcessDefExt> bpmProcDef = bpmDefinitionService
				.getBpmProcessDef(def.getBpmnDefId());
		BpmDefExtProperties extProperties = null;
		if (bpmProcDef != null && bpmProcDef.getProcessDefExt() != null
				&& bpmProcDef.getProcessDefExt().getExtProperties() != null) {
			extProperties = bpmProcDef.getProcessDefExt().getExtProperties();
		} else {
			extProperties = new BpmDefExtProperties();
		}
		request.setAttribute("bpmDefUtil", new ProcessDefExtUtil2(
				(DefaultBpmDefinition) def, extProperties));
		request.setAttribute("vars", bpmDefVarsService.selectMap(defId));
		if (StringUtil.isNotEmpty(def.getBpmnDefId())) {
			BpmDefLayout layout = diagramService.getLayoutByDefId(def
					.getDefId());
			request.setAttribute("bpmDefLayout", layout);
		}
		return "/bpm/def/definition/definitionEdit";
	}

	/**
	 * 删除流程定义页面
	 * 
	 * @param request
	 * @param response
	 * @param redirectAttributes
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("{defId}/delete")
	public void delete(HttpServletRequest request,
			HttpServletResponse response, @PathVariable String defId)
			throws Exception {
		String msg = "删除成功";
		try {
			bpmDefinitionService.removeBpmDefinition(defId);
			bpmDefVarsService.delete(defId);
		} catch (Exception e) {
			e.printStackTrace();
			msg = "操作出错：" + e.getMessage();
		}
		request.setAttribute(LIST_CALL_IN_MESSAGE, msg);
		request.getRequestDispatcher("/bpm/def/definition/list").forward(
				request, response);
	}

	/**
	 * 返回流程列表
	 * 
	 * @param request
	 * @param response
	 * @param redirectAttributes
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("list")
	public String list(HttpServletRequest request,
			HttpServletResponse response, DefaultBpmDefinition bpmDef,
			RedirectAttributes redirectAttributes) throws Exception {
		DefaultQueryFilter queryFilter = (DefaultQueryFilter) getQuerFilter(
				request, null);
		FieldLogic andFieldLogic = new DefaultFieldLogic(FieldRelation.AND);
		queryFilter.setFieldLogic(andFieldLogic);
		queryFilter.addFilter("is_main_", "Y", QueryOP.EQUAL);
		List<FieldSort> fieldSorts = new ArrayList<FieldSort>();
		fieldSorts.add(new DefaultFieldSort("create_time_", Direction
				.fromString("DESC")));
		queryFilter.setFieldSortList(fieldSorts);
		if (StringUtil.isNotEmpty(bpmDef.getName())) {
			queryFilter.addFilter("name_", bpmDef.getName(), QueryOP.LIKE);
		}
		if (StringUtil.isNotEmpty(bpmDef.getDefKey())) {
			queryFilter
					.addFilter("def_key_", bpmDef.getDefKey(), QueryOP.LIKE);
		}
		PageList<DefaultBpmDefinition> bpmDefinitionList = (PageList<DefaultBpmDefinition>) bpmDefinitionManager
				.query(queryFilter);
		Page<DefaultBpmDefinition> page = new Page<DefaultBpmDefinition>(
				bpmDefinitionList);
		request.setAttribute("page", page);
		request.setAttribute("bpmDef", bpmDef);
		Object msg = request.getAttribute(LIST_CALL_IN_MESSAGE);
		if (msg != null) {
			addMessage(redirectAttributes, msg.toString());
		}
		return "/bpm/def/definition/definitionList";
	}

	/**
	 * 流程通过flex 在线设置流程
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("design")
	public String design(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String defId = request.getParameter("defId");
		if (StringUtil.isNotEmpty(defId)) {
			DefaultBpmDefinition po = bpmDefinitionManager.getById(defId);
			request.setAttribute("bpmDefinition", po);
			request.setAttribute("name", po.getName());
		} else {
			request.setAttribute("name", "未命名");
		}

		// xml流程分类
		StringBuffer sb = new StringBuffer("<folder id='0' label='全部'>");
		sb.append("<folder id='1' label='SAP流程'></folder>");
		sb.append("<folder id='2' label='OSSP流程'></folder></folder>");

		// if (bpmDefinition.getTypeId() != null) {
		// msg.append("<typeName>流程测试</typeName>");
		// msg.append("<typeId>1</typeId>");
		// }
		request.setAttribute("xmlRecord", sb.toString());
		request.setAttribute("defId", defId); // defId流程定义id
		return "/bpm/def/definition/definitionDesign";
	}

	/**
	 * 处理泳道池的泳道Lane 的ID重复的问题
	 * 
	 * @param defXml
	 */
	private String dealPool(String defXml) {
		// 控制ID不重复
		int v = 1;
		int h = 1;
		// 处理垂直泳道池
		Pattern vRegex = Pattern.compile("<bg:VLane\\s*(id=\"\\w+\")\\s*");
		Matcher vRegexMatcher = vRegex.matcher(defXml);
		while (vRegexMatcher.find()) {
			String vLane = "id=\"vLane" + v + "\"";
			defXml = defXml.replaceFirst(vRegexMatcher.group(1), vLane);
			v++;
		}
		// 处理水平泳道池
		Pattern hRegex = Pattern.compile("<bg:HLane\\s*(id=\"\\w+\")\\s*");
		Matcher hRegexMatcher = hRegex.matcher(defXml);
		while (hRegexMatcher.find()) {
			String hLane = "id=\"hLane" + h + "\"";
			defXml = defXml.replaceFirst(hRegexMatcher.group(1), hLane);
			h++;
		}
		return defXml;
	}

	private DefaultBpmDefinition getFromRequest(HttpServletRequest request)
			throws Exception {
		String typeId = RequestUtil.getString(request, "bpmDefinition.typeId"); // 流程分类
		String subject = RequestUtil
				.getString(request, "bpmDefinition.subject"); // 流程标题
		String defKey = RequestUtil.getString(request, "bpmDefinition.defKey"); // 流程key
		String descp = RequestUtil.getString(request, "bpmDefinition.descp"); // description
		String defXml = RequestUtil.getString(request, "bpmDefinition.defXml"); // defXml
		defXml = defXml.replace("''", "'");
		// 处理泳道池的泳道Lane 的ID重复的问题
		defXml = this.dealPool(defXml);

		String reason = RequestUtil.getString(request, "bpmDefinition.reason");// reason
		String defId = RequestUtil.getString(request, "bpmDefinition.defId");

		DefaultBpmDefinition bpmDefinition = null;
		if (StringUtils.isNotEmpty(defId)) {
			bpmDefinition = bpmDefinitionManager.getById(defId);
		}
		if (bpmDefinition == null) {
			bpmDefinition = new DefaultBpmDefinition();
			if (StringUtils.isNotEmpty(defKey)) {
				bpmDefinition.setDefKey(defKey);
			}
		}
		// 设置属性值
		if (StringUtils.isNotEmpty(typeId)) {
			bpmDefinition.setTypeId(typeId);
		}
		if (StringUtils.isNotEmpty(subject)) {
			bpmDefinition.setName(subject);
		}
		if (StringUtils.isNotEmpty(reason)) {
			bpmDefinition.setReason(reason);
		}
		if (StringUtils.isNotEmpty(descp)) {
			bpmDefinition.setDesc(descp);
		} else {
			bpmDefinition.setDesc(subject);
		}
		if (StringUtils.isNotEmpty(defXml)) {
			bpmDefinition
					.setDefXml("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
							+ defXml);
		}

		return bpmDefinition;
	}

	/**
	 * flex，保存发布流程信息。
	 * 
	 * @param request
	 * @param response
	 * @return ModelAndView
	 * @throws Exception
	 */
	@RequestMapping("flexDefSave")
	public ModelAndView flexDefSave(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		Boolean isDeploy = Boolean.parseBoolean(request.getParameter("deploy"));
		DefaultBpmDefinition bpmDefinition = this.getFromRequest(request);
		String resultMsg = null;
		try {
			if (isDeploy) {
				bpmDefinition.setDesigner(DesignerType.FLASH.name());
				if (StringUtils.isNotEmpty(bpmDefinition.getDefId())) {
					DefaultBpmDefinition oldBpmDefinition = bpmDefinitionManager
							.getByDefIdCascadeXml(bpmDefinition.getDefId());
					BeanUtils.copyNotNullProperties(oldBpmDefinition,
							bpmDefinition);
					bpmDefinitionService.deploy(oldBpmDefinition);
					resultMsg = "成功发布新版本流程定义！";
				} else {
					bpmDefinitionService.deploy(bpmDefinition);
					resultMsg = "成功发布流程定义！";
				}
			} else if (StringUtils.isNotEmpty(bpmDefinition.getDefId())) {
				DefaultBpmDefinition oldBpmDefinition = bpmDefinitionManager
						.getById(bpmDefinition.getDefId());
				BeanUtils
						.copyNotNullProperties(oldBpmDefinition, bpmDefinition);
				bpmDefinitionService.updateBpmDefinition(oldBpmDefinition);
				resultMsg = "成功更新流程定义！";
			}
			response.getWriter().print(resultMsg);
		} catch (Exception ex) {
			ex.printStackTrace();
			response.getWriter().print("操作失败！");
		}
		return null;
	}

	/**
	 * 在流程在线设计中获取分类的所有流程
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("getFlowListByTypeId")
	public void getFlowListByTypeId(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		StringBuffer msg = new StringBuffer(
				"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Result>");
		msg.append("</Result>");
		PrintWriter out = response.getWriter();
		out.println(msg.toString());
	}

	/**
	 * 流程在线设计，根据defId获取流程对应的详细信息
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("flexGet")
	public ModelAndView flexGet(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String defId = request.getParameter("defId");
		DefaultBpmDefinition bpmDefinition = null;
		if (StringUtil.isNotEmpty(defId)) {
			bpmDefinition = bpmDefinitionManager.getById(defId);
		} else {
			bpmDefinition = new DefaultBpmDefinition();
		}
		StringBuffer msg = new StringBuffer(
				"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Result>");
		msg.append("<defId>" + bpmDefinition.getDefId() + "</defId>");
		msg.append("<defXml>" + bpmDefinition.getDefXml() + "</defXml>");
		// if (bpmDefinition.getTypeId() != null) {
		// msg.append("<typeName>流程测试</typeName>");
		// msg.append("<typeId>1</typeId>");
		// }
		if (StringUtil.isNotEmpty(defId)) {
			if ("1".equals(bpmDefinition.getTypeId())) {
				msg.append("<typeName>SAP流程</typeName>");
				msg.append("<typeId>1</typeId>");
			} else if ("2".equals(bpmDefinition.getTypeId())) {
				msg.append("<typeName>OSSP流程</typeName>");
				msg.append("<typeId>2</typeId>");
			}
		}
		msg.append("<subject>" + bpmDefinition.getName() + "</subject>");
		msg.append("<defKey>" + bpmDefinition.getDefKey() + "</defKey>");
		msg.append("<descp>" + bpmDefinition.getDesc() + "</descp>");
		msg.append("<versionNo>" + bpmDefinition.getVersion() + "</versionNo>");
		msg.append("</Result>");

		PrintWriter out = response.getWriter();
		out.println(msg.toString());
		return null;
	}

}
